home *** CD-ROM | disk | FTP | other *** search
- /*
- File: StorageClassDriver.c
-
- Contains: Contains the state machine for configuring the interface,
- and all routines needed by the rest of the class driver.
-
- Version: 1.3
-
- Copyright: © 1998-2000 by Apple Computer, Inc., all rights reserved.
- */
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- includes
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- #include <DriverGestalt.h> // For interface type used in Name reg search.
- #include <DriverServices.h>
- #include <MacTypes.h>
- #include <USB.h>
-
- #include "StorageClassPublicAPI.h"
- #include "StorageClassDriver.h"
-
- // Includes for the Protocols
- #include "StorageClassCBIProtocol.h"
- #include "StorageClassBulkProtocol.h"
- #include "StorageDeviceConfiguration.h"
-
- // The Wake workaround is to handle devices that do not respond favorably to
- // Suspend/Resume. Usually these devices will reset to an un initialized state.
- // The wake workaround sends a command to the device to determine if it has reset
- // itself and therefore no longer has its address set. The workaround will reset
- // the device and then reconfigure its interface.
- // Flag to turn wake workaround on and off
- #define DO_WAKE_WORKAROUND true
-
- // These states are used by StorageDeviceInitiateConfiguration
- enum
- {
- kGetFullConfiguration = 1,
- kSetConfig,
- kFindStorageInterface,
- kNewInterfaceRef,
-
- kStorageConfigureInterface,
- kStorageFindInterruptPipe,
- kStorageFindBulkInPipe,
- kStorageFindBulkOutPipe,
-
- kStorageGetVendorDescriptorlength,
- kStorageGetVendorDescriptorString,
- kStorageGetProductDescriptorlength,
- kStorageGetProductDescriptorString,
-
- kReturnFromDriver = 0x1000,
- kRetryTransaction = 0x2000,
- kCompletionPending = 0x8000
- };
-
- // Structure to hold our Globals
- struct StorageClassInfo
- {
- USBPB usbPB; // Configuration block
- USBPipeRef interruptPipeRef; // Interrupt pipe reference
- USBPipeRef readPipeRef; // Bulk in pipe reference
- USBPipeRef writePipeRef; // Bulk out pipe reference
-
- // device: configuration and interface details
- USBDeviceRef interfaceRef; // USB device reference
- USBDeviceRef deviceRef; // USB device reference
- UInt32 interfaceNumber;
-
- USBConfigurationDescriptorPtr pFullConfigDescriptor;
-
- // These two fields are used by the driver to hold the entire descriptor structure that
- // is returned from the drive during the device configuration sequence. This is used
- // when loaded as a device (not interface) driver and by the wake from sleep reset sequence.
- USBConfigurationDescriptor configDescriptor;
- USBInterfaceDescriptor interfaceDescriptor[10];
-
- USBDeviceDescriptor deviceDescriptor; // copy for local reference
- USBInterfaceDescriptorPtr pInterfaceDescriptor; // copy for local reference
-
- Str255 usbVendorNameString; // Name of vendor
- Str255 usbProductNameString; // Name of Product
-
- // class driver async transactions
- SInt32 retryCount; // automatically retry transactions
-
- // Class Driver configuration information
- UInt32 configurationStatus; // Current state of configuration
- Boolean classInUse; // Used in StorageClassDriverNotifyProc to prevent removal by expert
- Boolean ROMDriverLocked; // Used in StorageClassDriverNotifyProc to prevent removal by expert
- };
- typedef struct StorageClassInfo StorageClassInfo;
-
- // Dispatch Table definitions for the Unit Table
- static UInt32 MyUSBGetVersion(void);
- static OSStatus StorageClassDriverInitialize(void);
- static OSStatus StorageClassDriverTerminate(void);
- static OSStatus StorageClassDriverControl(UInt32 theControlSelector, void *theControlData);
- static OSStatus StorageClassDriverStatus(UInt32 theInfoSelector, void *theInfo);
- static OSStatus StorageClassDriverExecuteCommand(StorageExecuteCommandPBPtr cmdPBPtr);
-
- StorageClassDispatchTable TheAppleStorageClassDispatchTable =
- {
- kDispatchTableVersion,
- StorageClassDriverInitialize,
- StorageClassDriverTerminate,
- StorageClassDriverControl,
- StorageClassDriverStatus,
- StorageClassDriverExecuteCommand
- };
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- globals
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static StorageClassInfo gStorageClassInfo; // Holds all of the common items
- static Boolean gBeenThereDoneThat = false; // Flag indicating if this driver has been called before
- static SInt8 gInSleepReset = 0; // Is the driver in the middle of an after sleep reset?
- static StorageExecuteCommandPBPtr gAfterSleepPBPtr = nil; // The StorageExecuteCommandPBPtr we received in the middle of a sleep reset
-
- #if (DO_WAKE_WORKAROUND==true)
- static Boolean inReset = false; // flag to indicate if the driver has already started a wakeup reset
- #endif
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- prototypes
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static Boolean ImmediateError(OSStatus err);
- static void ConvertUnicodeToASCII( UInt8 *stringBuffer );
- static void InitDescriptorStringPB( USBPB *usbPB, UInt8 stringIndex, UInt8 *stringBuffer, UInt16 stringLength );
- static USBInterfaceDescriptorPtr GetInterfaceDescriptor( LogicalAddress pConfigDesc, UInt32 ReqInterface );
- static void StorageDeviceInitiateConfiguration(USBPB* pb);
- static void StorageDeviceConfigureCompletion(USBPB* pb);
- static Boolean IsThisTheBootDevice ( USBDeviceRef usbRefNum );
-
- // Protos for the SUSPEND/RESUME problem
- static void StartResetDeviceAfterSleep( void );
- static void ResetDeviceAfterSleep( USBPB *usbPB );
- static void ResetDeviceAfterSleepCompletion( USBPB *usbPB );
-
- //****************************************************************************************************
- //Accessors for Global Info
- UInt8 GetInterfaceSubclass( void )
- {
- return gStorageClassInfo.pInterfaceDescriptor->interfaceSubClass;
- }
-
- UInt32 GetInterfaceNumber( void )
- {
- return gStorageClassInfo.interfaceNumber;
- }
-
- USBDeviceRef GetInterfaceRef( void )
- {
- return gStorageClassInfo.interfaceRef; // USB device reference
- }
-
- USBPipeRef GetBulkInPipeRef( void )
- {
- return gStorageClassInfo.readPipeRef;
- }
-
- USBPipeRef GetBulkOutPipeRef( void )
- {
- return gStorageClassInfo.writePipeRef;
- }
-
- USBPipeRef GetInterruptPipeRef( void )
- {
- return gStorageClassInfo.interruptPipeRef;
- }
-
- void InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock)
- {
- USBCompletion usbCompletion = paramblock->usbCompletion;
- UInt32 usbRefcon = paramblock->usbRefcon;
-
- BlockZero( paramblock, sizeof(USBPB) );
-
- paramblock->pbLength = sizeof(USBPB);
- paramblock->pbVersion = kUSBCurrentPBVersion;
- paramblock->usbReference = theDeviceRef;
- paramblock->usbCompletion = usbCompletion;
- paramblock->usbRefcon = usbRefcon;
- paramblock->usbStatus = kRequestPending; // Set status to pending so we can when a request is complete
- }
-
-
- Boolean ImmediateError(OSStatus err)
- {
- return((err != kUSBPending) && (err != noErr) );
- }
-
- Boolean IsThisASupportedProtocol( UInt8 theProtocol )
- {
- if (( theProtocol == kProtocolCBI ) || ( theProtocol == kProtocolCBNoInterrupt ) || ( theProtocol == kProtocolBulkOnly))
- {
- // This is indeed a protocol the driver understands
- return true;
- }
-
- // The driver does not know of this protocol
- return false;
- }
-
- OSStatus ClearFeatureEndpointStall( USBPB *usbPB, USBPipeRef pipeRefForEndpoint, USBCompletion completionProc, UInt32 refCon)
- {
- // Make sure that the Data Toggles are reset before doing the Clear Stall.
- USBResetPipeByReference( pipeRefForEndpoint );
-
- InitParamBlock( pipeRefForEndpoint, usbPB); // Read the Status from the interrupt
-
- usbPB->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBNone, kUSBStandard, kUSBEndpoint);
- usbPB->usb.cntl.BRequest = kUSBRqClearFeature;
- usbPB->usb.cntl.WValue = 0;
- usbPB->usb.cntl.WIndex = 0;
-
- usbPB->usbBuffer = nil;
- usbPB->usbReqCount = 0;
- usbPB->usbCompletion = completionProc;
- usbPB->usbRefcon = refCon;
-
- // If this is not the default pipe, let the
- // USB Expert figure out the endpoint number
- if ( pipeRefForEndpoint != GetInterfaceRef())
- {
- usbPB->usbFlags = kUSBNo5SecTimeout | kUSBAddressRequest;
- }
-
- return USBDeviceRequest( usbPB );
- }
-
- // Buffer must be at least 2 bytes
- OSStatus GetStatusEndpointStatus( USBPB *usbPB, USBPipeRef pipeRefForEndpoint, USBCompletion completionProc, Ptr Buffer, UInt32 refCon)
- {
- InitParamBlock( pipeRefForEndpoint, usbPB); // Read the Status from the interrupt
-
- usbPB->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBEndpoint);
- usbPB->usb.cntl.BRequest = kUSBRqGetStatus;
- usbPB->usb.cntl.WValue = 0;
- usbPB->usb.cntl.WIndex = 0;
-
- usbPB->usbBuffer = Buffer;
- usbPB->usbReqCount = 2;
- usbPB->usbCompletion = completionProc;
- usbPB->usbRefcon = refCon;
-
- // If this is not the default pipe, let the
- // USB Expert figure out the endpoint number
- if ( pipeRefForEndpoint != GetInterfaceRef())
- {
- usbPB->usbFlags = kUSBNo5SecTimeout | kUSBAddressRequest;
- }
-
- return USBDeviceRequest( usbPB );
- }
-
- void ConvertUnicodeToASCII( UInt8 *stringBuffer )
- {
- UInt8 stringLength;
- UInt8 loopCount;
-
- stringLength = stringBuffer[0]/2;
- for (loopCount = 0; loopCount< stringLength; loopCount++)
- {
- stringBuffer[loopCount+1] = stringBuffer[(loopCount+1)*2];
- }
-
- stringBuffer[0] = stringLength-1;
- }
-
- void InitDescriptorStringPB( USBPB *usbPB, UInt8 stringIndex, UInt8 *stringBuffer, UInt16 stringLength)
- {
- InitParamBlock( gStorageClassInfo.interfaceRef, usbPB);
-
- usbPB->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);
- usbPB->usb.cntl.BRequest = kUSBRqGetDescriptor;
- usbPB->usb.cntl.WValue = 0x0300 | stringIndex;
- usbPB->usb.cntl.WIndex = 0x409;
- usbPB->usb.cntl.reserved4 = HostToUSBWord(stringLength);
-
- usbPB->usbBuffer = stringBuffer;
- usbPB->usbReqCount = stringLength;
-
- usbPB->usbFlags = kUSBNo5SecTimeout;
- }
-
- USBInterfaceDescriptorPtr GetInterfaceDescriptor( LogicalAddress pConfigDesc, UInt32 ReqInterface )
- {
- UInt32 totalLength;
- void * pEndOfDescriptors;
- USBInterfaceDescriptorPtr pMyIntDesc;
- USBDescriptorHeaderPtr pCurrentDesc;
- UInt32 anAddress, anOffset;
-
- totalLength = ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength;
- pEndOfDescriptors = (Ptr)pConfigDesc + totalLength; // get the total length and add it to the start of the config space
- pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc; // point the currentdesc to the start of the config space
-
- while (pCurrentDesc < pEndOfDescriptors) // as long as we haven't exhausted all the descriptors
- {
- if (pCurrentDesc->descriptorType == kUSBInterfaceDesc) // look at the current descriptor
- {
- pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc; // if it's an interface descriptor
- if (pMyIntDesc->interfaceNumber == ReqInterface) // see if it's the request descriptor
- {
- return pMyIntDesc; // current descriptor pointer
- }
- }
-
- anAddress = (unsigned long) pCurrentDesc; // Nope, that either wasn't an interface descriptor
- anOffset = (unsigned long) pCurrentDesc->length;
- anAddress += anOffset;
- pCurrentDesc = (USBDescriptorHeaderPtr) anAddress;
- } // or it was, but not the interface we're looking for.
-
- return nil;
- }
-
- //****************************************************************************************************
- //
- // StorageClassDriverAPI.c calls end up here...
- //
- //****************************************************************************************************
-
- OSStatus StorageClassDriverInitialize(void)
- {
- gStorageClassInfo.classInUse = true;
- gInSleepReset = 0;
- gAfterSleepPBPtr = nil;
- return noErr;
- }
-
- OSStatus StorageClassDriverTerminate(void)
- {
- gStorageClassInfo.ROMDriverLocked = false;
- gStorageClassInfo.classInUse = false;
- return noErr;
- }
-
- OSStatus StorageClassDriverControl( UInt32 theControlSelector, void *theControlData)
- {
- OSStatus status;
-
- switch (theControlSelector)
- {
- case kUSBStorageControlAbortCommand:
- {
- if((gStorageClassInfo.pInterfaceDescriptor->interfaceProtocol == kProtocolBulkOnly) || (gStorageClassInfo.deviceDescriptor.protocol == kProtocolBulkOnly))
- {
- status = StorageClassBulkOnlyAbortCommand( (StorageExecuteCommandPBPtr) theControlData );
- }
- else
- {
- status = StorageClassCBIAbortCommand( (StorageExecuteCommandPBPtr) theControlData );
- }
- }
- break;
-
- case kUSBStorageControlSetParentsRefNumber:
- {
- USBDeviceRef theDeviceRef;
-
- theDeviceRef = *(USBDeviceRef *)theControlData;
-
- if ( theDeviceRef != 0 )
- {
- // If the passed in reference is not zero, we are an interface driver
- // so we need to save the device ref of our parent node, else if it is
- // zero, we are a device driver and the deviceRef we have is valid.
- gStorageClassInfo.deviceRef = theDeviceRef;
- }
- }
- break;
-
- default:
- {
- status = controlErr;
- }
- break;
- }
-
- return status;
- }
-
-
- OSStatus StorageClassDriverStatus( UInt32 theInfoSelector, void *theInfo)
- {
- OSStatus status;
-
- switch (theInfoSelector)
- {
- case kUSBStorageStatusGetServicesStatus: // Return the current confifuration status
- {
- if ( gInSleepReset == 1 )
- {
- *((UInt32*) theInfo) = kUSBStorageServicesConfigureComplete;
- }
- else
- {
- *((UInt32*) theInfo) = gStorageClassInfo.configurationStatus;
- }
-
- status = noErr;
- }
- break;
-
- case kUSBStorageStatusGetRemovalStatus:
- {
- *((Boolean*) theInfo) = !gStorageClassInfo.classInUse;
- status = noErr;
- }
- break;
-
- case kUSBStorageStatusGetVendorStringPtr:
- {
- if( PStrLen(gStorageClassInfo.usbVendorNameString) == 0 )
- {
- *((StringPtr *) theInfo) = nil;
- }
- else
- {
- *((StringPtr *) theInfo) = gStorageClassInfo.usbVendorNameString;
- }
-
- status = noErr;
- }
- break;
-
- case kUSBStorageStatusGetProductStringPtr:
- {
- if( PStrLen(gStorageClassInfo.usbProductNameString) == 0 )
- {
- *((StringPtr *) theInfo) = nil;
- }
- else
- {
- *((StringPtr *) theInfo) = gStorageClassInfo.usbProductNameString;
- }
-
- status = noErr;
- }
- break;
-
- case kUSBStorageStatusGetDeviceReleaseNumber:
- {
- *((UInt16 *) theInfo) = USBToHostWord (gStorageClassInfo.deviceDescriptor.devRel);
- status = noErr;
- }
- break;
-
- default:
- {
- status = statusErr;
- }
- break;
-
- }
-
- return status;
- }
-
-
- // All device requests come through here
- OSStatus StorageClassDriverExecuteCommand( StorageExecuteCommandPBPtr cmdPBPtr )
- {
- OSStatus status;
-
- if ( gInSleepReset == 1 )
- {
- // The class driver is currently in the middle of an
- // after sleep reset sequence. Save the parameter block
- // for when it is done and tell the UT driver that it is pending.
- #if (DO_WAKE_WORKAROUND==true)
- if (((( cmdPBPtr->flags & kStorageDataIn) == kStorageDataIn ) || (( cmdPBPtr->flags & kStorageDataOut) == kStorageDataOut )) && ( cmdPBPtr->expectedCount >= 0x0200L))
- {
- gAfterSleepPBPtr = cmdPBPtr;
- cmdPBPtr->status = kRequestPending;
-
- if ( inReset == false )
- {
- inReset = true;
- StartResetDeviceAfterSleep();
- }
-
- return kRequestPending;
- }
- else
- {
- //gAfterSleepPBPtr = cmdPBPtr;
- cmdPBPtr->status = ioErr;
- return ioErr;
- }
- #else
- gAfterSleepPBPtr = cmdPBPtr;
- cmdPBPtr->status = kRequestPending;
- return kRequestPending;
- #endif
- }
-
- // Make sure we have been able to configure the device
- if ( gStorageClassInfo.configurationStatus != kUSBStorageServicesConfigureComplete )
- {
- return kClassNotConfiguredError;
- }
-
- if((gStorageClassInfo.pInterfaceDescriptor->interfaceProtocol == kProtocolBulkOnly) || (gStorageClassInfo.deviceDescriptor.protocol == kProtocolBulkOnly))
- {
- status = StorageClassBulkOnlyExecuteCommand( cmdPBPtr );
- }
- else
- {
- status = StorageClassCBIExecuteCommand( cmdPBPtr );
- }
-
- return status;
- }
-
-
- void StorageDeviceInitiateConfiguration(USBPB *usbPB)
- {
- OSStatus myErr;
-
- switch(usbPB->usbRefcon & ~kRetryTransaction)
- {
- case kGetFullConfiguration:
- {
- gStorageClassInfo.pFullConfigDescriptor = &gStorageClassInfo.configDescriptor;
- InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
-
- usbPB->usb.cntl.WIndex = 0;
- usbPB->usb.cntl.WValue = 1;
- usbPB->usbRefcon |= kCompletionPending;
- usbPB->usbReqCount = sizeof(USBConfigurationDescriptor)+(sizeof(USBInterfaceDescriptor)*10);
- usbPB->usbBuffer = gStorageClassInfo.pFullConfigDescriptor;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
-
- //myErr = USBGetFullConfigurationDescriptor(usbPB);
- myErr = USBGetConfigurationDescriptor(usbPB);
- if(ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kSetConfig:
- {
- InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
-
- usbPB->usb.cntl.WValue = gStorageClassInfo.pFullConfigDescriptor->configValue; // Use configuration ID value from descriptor
- usbPB->usbRefcon |= kCompletionPending;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- myErr = USBSetConfiguration(usbPB);
- if(ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kFindStorageInterface:
- {
- InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
- usbPB->usbClassType = kDeviceClass;
- usbPB->usbSubclass = kDeviceSubClass;
- usbPB->usbRefcon |= kCompletionPending;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
-
- myErr = USBFindNextInterface(usbPB);
- if(ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kNewInterfaceRef:
- {
- InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
- usbPB->usb.cntl.WIndex = gStorageClassInfo.interfaceNumber;
- usbPB->usbRefcon |= kCompletionPending;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
-
- myErr = USBNewInterfaceRef(usbPB);
- if(ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kStorageConfigureInterface:
- {
- InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
-
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- usbPB->usbRefcon |= kCompletionPending;
-
- myErr = USBConfigureInterface(usbPB);
- if (ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kStorageFindInterruptPipe:
- {
- InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
-
- usbPB->usbFlags = kUSBIn;
- usbPB->usbClassType = kUSBInterrupt;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- usbPB->usbRefcon |= kCompletionPending;
-
- myErr = USBFindNextPipe( usbPB );
- if (ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- usbPB->usbRefcon = kReturnFromDriver;
- }
- }
- break;
-
- case kStorageFindBulkInPipe:
- {
- InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
-
- usbPB->usbFlags = kUSBIn;
- usbPB->usbClassType = kUSBBulk;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- usbPB->usbRefcon |= kCompletionPending;
-
- myErr = USBFindNextPipe( usbPB );
- if (ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- usbPB->usbRefcon = kReturnFromDriver;
- }
- }
- break;
-
- case kStorageFindBulkOutPipe:
- {
- InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
-
- usbPB->usbFlags = kUSBOut;
- usbPB->usbClassType = kUSBBulk;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- usbPB->usbRefcon |= kCompletionPending;
-
- myErr = USBFindNextPipe( usbPB );
- if (ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- usbPB->usbRefcon = kReturnFromDriver;
- }
- }
- break;
-
-
- case kStorageGetVendorDescriptorlength:
- {
- InitDescriptorStringPB( usbPB, gStorageClassInfo.deviceDescriptor.manuIdx, gStorageClassInfo.usbVendorNameString, 2);
- usbPB->usbRefcon |= kCompletionPending;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- myErr = USBDeviceRequest(usbPB);
- if (ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kStorageGetVendorDescriptorString:
- {
- UInt16 stringLength;
-
- stringLength = gStorageClassInfo.usbVendorNameString[0];
- InitDescriptorStringPB( usbPB, gStorageClassInfo.deviceDescriptor.manuIdx, gStorageClassInfo.usbVendorNameString, stringLength);
- usbPB->usbRefcon |= kCompletionPending;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- myErr = USBDeviceRequest(usbPB);
- if (ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kStorageGetProductDescriptorlength:
- {
- InitDescriptorStringPB( usbPB, gStorageClassInfo.deviceDescriptor.prodIdx, gStorageClassInfo.usbProductNameString, 2);
- usbPB->usbRefcon |= kCompletionPending;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- myErr = USBDeviceRequest(usbPB);
- if (ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kStorageGetProductDescriptorString:
- {
- UInt16 stringLength;
-
- stringLength = gStorageClassInfo.usbProductNameString[0];
- InitDescriptorStringPB( usbPB, gStorageClassInfo.deviceDescriptor.prodIdx, gStorageClassInfo.usbProductNameString, stringLength);
- usbPB->usbRefcon |= kCompletionPending;
- usbPB->usbCompletion = StorageDeviceConfigureCompletion;
- myErr = USBDeviceRequest(usbPB);
- if (ImmediateError(myErr))
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- }
- }
- break;
-
- case kReturnFromDriver:
- break;
-
- default:
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- usbPB->usbRefcon = kReturnFromDriver;
- }
- break;
- }
-
- // At this point the control is returned to the system. If a USB transaction
- // has been initiated, then it will call the Complete procs
- // (below) to handle the results of the transaction.
- }
-
- void StorageDeviceConfigureCompletion(USBPB *usbPB)
- {
- // We should only retry if the error is a USB transaction problem
- // Device errors are handled outside of the state machine.
- if ((usbPB->usbStatus != noErr) && (usbPB->usbStatus != kUSBPending))
- {
- usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
- usbPB->usbRefcon |= kRetryTransaction;
- gStorageClassInfo.retryCount--;
- if (!gStorageClassInfo.retryCount)
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- usbPB->usbRefcon = kReturnFromDriver;
- return;
- }
- }
- else
- {
- usbPB->usbRefcon &= ~kRetryTransaction;
- gStorageClassInfo.retryCount = kStorageRetryCount;
- }
-
- if (usbPB->usbRefcon & kCompletionPending)
- {
- usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
- switch(usbPB->usbRefcon)
- {
- case kGetFullConfiguration:
- {
- usbPB->usbRefcon = kSetConfig;
- }
- break;
-
- case kSetConfig:
- {
- usbPB->usbRefcon = kFindStorageInterface;
- }
- break;
-
- case kFindStorageInterface:
- {
- gStorageClassInfo.interfaceNumber = usbPB->usb.cntl.WIndex;
- gStorageClassInfo.pInterfaceDescriptor = GetInterfaceDescriptor( gStorageClassInfo.pFullConfigDescriptor, gStorageClassInfo.interfaceNumber );
- usbPB->usbRefcon = kNewInterfaceRef;
- }
- break;
-
- case kNewInterfaceRef:
- {
- gStorageClassInfo.interfaceRef = usbPB->usbReference;
- usbPB->usbRefcon = kStorageConfigureInterface;
- }
- break;
-
- case kStorageConfigureInterface:
- {
- if((gStorageClassInfo.pInterfaceDescriptor->interfaceProtocol == kProtocolBulkOnly) || (gStorageClassInfo.deviceDescriptor.protocol == kProtocolBulkOnly))
- {
- // Since this is a Bulk Only device, do not look for interrupt
- gStorageClassInfo.interruptPipeRef = 0; // We have no interrupt, so set ref to zero
- usbPB->usbRefcon = kStorageFindBulkInPipe;
- }
- else
- {
- usbPB->usbRefcon = kStorageFindInterruptPipe;
- }
- }
- break;
-
- case kStorageFindInterruptPipe:
- {
- gStorageClassInfo.interruptPipeRef = usbPB->usbReference;
-
- #if defined( FOR_VENDORSPECIFIC )
- usbPB->usbRefcon = kStorageFindBulkInPipe;
- #else
- if(((gStorageClassInfo.pInterfaceDescriptor->interfaceProtocol == kProtocolCBI) || (gStorageClassInfo.deviceDescriptor.protocol == kProtocolCBI))
- && (gStorageClassInfo.interruptPipeRef == 0))
- {
- // This is a CBI device and must have an interrupt. If no Interrupt pipe could be
- // opened, report an error and halt drive configuration.
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- usbPB->usbRefcon = kReturnFromDriver;
- }
- else
- {
- usbPB->usbRefcon = kStorageFindBulkInPipe;
- }
- #endif /* FOR_VENDORSPECIFIC */
- }
- break;
-
- case kStorageFindBulkInPipe:
- {
- // Save the pipe reference
- gStorageClassInfo.readPipeRef = usbPB->usbReference;
-
- // Onto the next state
- usbPB->usbRefcon = kStorageFindBulkOutPipe;
- }
- break;
-
- case kStorageFindBulkOutPipe:
- {
- gStorageClassInfo.writePipeRef = usbPB->usbReference;
-
- if ( gStorageClassInfo.deviceDescriptor.manuIdx == 0 )
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureComplete; // Flag for client to determine that we are now configured
- usbPB->usbRefcon = kReturnFromDriver;
- }
- else
- {
- usbPB->usbRefcon = kStorageGetVendorDescriptorlength;
- }
- }
- break;
-
- case kStorageGetVendorDescriptorlength:
- {
- usbPB->usbRefcon = kStorageGetVendorDescriptorString;
- }
- break;
-
- case kStorageGetVendorDescriptorString:
- {
- ConvertUnicodeToASCII( gStorageClassInfo.usbVendorNameString );
- usbPB->usbRefcon = kStorageGetProductDescriptorlength;
- }
- break;
-
- case kStorageGetProductDescriptorlength:
- {
- usbPB->usbRefcon = kStorageGetProductDescriptorString;
- }
- break;
-
- case kStorageGetProductDescriptorString:
- {
- ConvertUnicodeToASCII( gStorageClassInfo.usbProductNameString );
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureComplete; // Flag for client to determine that we are now configured
- usbPB->usbRefcon = kReturnFromDriver;
- }
- break;
-
- default:
- {
- if ( usbPB->usbStatus == noErr )
- {
- usbPB->usbRefcon = kReturnFromDriver;
- }
- }
- break;
- }
- }
-
- if ( usbPB->usbStatus == noErr )
- {
- if (!(usbPB->usbRefcon & kReturnFromDriver))
- {
- StorageDeviceInitiateConfiguration(usbPB);
- }
- else
- {
- if ( gInSleepReset == 1 )
- {
- DecrementAtomic8( &gInSleepReset );
- if ( gInSleepReset < 0)
- {
- gInSleepReset = 0;
- }
-
- if ( gAfterSleepPBPtr != nil )
- {
- OSStatus status;
-
- // We got a command during the reset, send it out now
- status = StorageClassDriverExecuteCommand( gAfterSleepPBPtr );
- if ( status != kRequestPending )
- {
- if(gAfterSleepPBPtr->completionProc != nil)
- {
- gAfterSleepPBPtr->status = kUSBInternalErr;
- (*gAfterSleepPBPtr->completionProc)( gAfterSleepPBPtr );
- }
- }
-
- gAfterSleepPBPtr = nil;
- }
- }
- }
- }
- else
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed;
- if ( gInSleepReset == 1 )
- {
- DecrementAtomic8( &gInSleepReset );
- if ( gInSleepReset < 0)
- {
- gInSleepReset = 0;
- }
-
- if ( gAfterSleepPBPtr != nil )
- {
- if(gAfterSleepPBPtr->completionProc != nil)
- {
- gAfterSleepPBPtr->status = kUSBInternalErr;
- (*gAfterSleepPBPtr->completionProc)( gAfterSleepPBPtr );
- }
-
- gAfterSleepPBPtr = nil;
- }
- }
- }
- }
-
- UInt32 MyUSBGetVersion(void)
- {
- UInt32 version;
-
- if ((Ptr) USBGetVersion != (Ptr) kUnresolvedCFragSymbolAddress)
- version = USBGetVersion();
- else
- version = 0; // version of USB is less than 1.3
- return version;
- }
-
- void StorageDriverEntry( USBDeviceRef deviceRef, USBDeviceDescriptorPtr deviceDescriptorPtr, USBInterfaceDescriptorPtr pInterfaceDescriptor )
- {
- if( gBeenThereDoneThat == false )
- {
- gBeenThereDoneThat = true;
-
- // Check for the correct version of the USB manager.
- // We are ok with all version later than 1.3
- if ((MyUSBGetVersion() & 0xffff0000) < kMinimumUSBMgrVersion) // Wrong USB version number so do NOT continue
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureFailed; // Flag for client to determine that configuration failed
- return ;
- }
-
- // Initialize the global data structures
- BlockZero(&gStorageClassInfo, sizeof(StorageClassInfo));
-
- gStorageClassInfo.retryCount = kStorageRetryCount;
- gStorageClassInfo.deviceDescriptor = *deviceDescriptorPtr; // keep a copy of the device descriptor
-
- // If we got loaded as an interface driver, save the interface descriptor and set our interface pointer
- // to point to it.
- if ( pInterfaceDescriptor != nil )
- {
- gStorageClassInfo.interfaceDescriptor[0] = *pInterfaceDescriptor;
- gStorageClassInfo.pInterfaceDescriptor = &gStorageClassInfo.interfaceDescriptor[0];
- }
- else
- {
- gStorageClassInfo.pInterfaceDescriptor = nil;
- }
-
- gStorageClassInfo.deviceRef = deviceRef;
- gStorageClassInfo.interfaceRef = deviceRef;
-
- InitParamBlock( deviceRef, &gStorageClassInfo.usbPB );
-
- // Start out at first state
- if (gStorageClassInfo.pInterfaceDescriptor != nil)
- {
- gStorageClassInfo.usbPB.usbRefcon = kStorageConfigureInterface;
- }
- else
- {
- gStorageClassInfo.usbPB.usbRefcon = kGetFullConfiguration;
- }
-
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureInProgress;
- StorageDeviceInitiateConfiguration(&gStorageClassInfo.usbPB);
- }
- }
-
-
- void StorageClassDriverFinalize( void )
- {
- OSStatus status;
-
- TheAppleStorageClassDispatchTable.dispatchTableVersion = 0;
-
- //
- // Make sure all pipes are finished with transactions by calling the USBAbortPipeByReference function
- //
- status = USBAbortPipeByReference(gStorageClassInfo.interfaceRef); // Control pipe
- status = USBAbortPipeByReference(gStorageClassInfo.interruptPipeRef); // Interrupt pipe
- status = USBAbortPipeByReference(gStorageClassInfo.readPipeRef); // Read pipe
- status = USBAbortPipeByReference(gStorageClassInfo.writePipeRef); // Write pipe
- }
-
- OSStatus StorageClassDriverNotifyProc(UInt32 notification, void* pointer, UInt32 refcon)
- {
- #pragma unused ( pointer, refcon )
- OSStatus status = noErr;
-
- switch ( notification )
- {
- case kNotifyDriverBeingRemoved:
- {
- // We were in sleep and now we are being notified of being removed.
- // This means that we were probably hibernating. Clear out the
- // sleep condition and if we received a command, return it with an error.
- DecrementAtomic8( &gInSleepReset );
- if ( gInSleepReset < 0 )
- {
- gInSleepReset = 0;
- }
-
- if ( gAfterSleepPBPtr != nil )
- {
- gStorageClassInfo.configurationStatus = kUSBStorageServicesTerminated;
- if(gAfterSleepPBPtr->completionProc != nil)
- {
- gAfterSleepPBPtr->status = kUSBInternalErr;
- (*gAfterSleepPBPtr->completionProc)( gAfterSleepPBPtr );
- }
-
- gAfterSleepPBPtr = nil;
- status = kUSBDeviceBusy;
- }
- else if (gStorageClassInfo.configurationStatus == kUSBStorageServicesConfigureInProgress)
- {
- // Don't allow removal if we are busy configuring the interface.
- status = kUSBDeviceBusy;
- }
- else if (gStorageClassInfo.classInUse == true)
- {
- // Don't allow removal until the UnitTable Driver says it's ok
- status = kUSBDeviceBusy;
- }
- else
- {
- status = noErr;
- }
- }
- break;
-
- case kNotifySystemSleepRequest:
- case kNotifySystemSleepDemand:
- {
- #if (DO_WAKE_WORKAROUND==true)
- inReset = false;
- #endif
- IncrementAtomic8( &gInSleepReset );
- if ( gInSleepReset > 1)
- {
- gInSleepReset = 1;
- }
-
- status = noErr;
- }
- break;
-
- case kNotifySystemSleepWakeUp:
- {
- #if (DO_WAKE_WORKAROUND==true)
- if ( inReset == true )
- {
- return noErr;
- }
-
- inReset = true;
- #endif
- IncrementAtomic8( &gInSleepReset );
- if ( gInSleepReset > 1)
- {
- gInSleepReset = 1;
- }
-
- StartResetDeviceAfterSleep();
- status = noErr;
- }
- break;
-
- case kNotifySystemSleepRevoke:
- {
- DecrementAtomic8( &gInSleepReset );
- if ( gInSleepReset < 0 )
- {
- gInSleepReset = 0;
- }
-
- if ( gAfterSleepPBPtr != nil )
- {
- OSStatus status;
-
- // We got a command between the sleep notification and
- // the sleep revoke notification, send it out now.
- status = StorageClassDriverExecuteCommand( gAfterSleepPBPtr );
- if ( status != kRequestPending )
- {
- if(gAfterSleepPBPtr->completionProc != nil)
- {
- gAfterSleepPBPtr->status = kUSBInternalErr;
- (*gAfterSleepPBPtr->completionProc)( gAfterSleepPBPtr );
- }
- }
-
- gAfterSleepPBPtr = nil;
- }
-
- status = noErr;
- }
- break;
-
- default:
- {
- // We don't know how to handle this request, return the appropriate error
- status = kUSBNotHandled;
- }
- }
-
- return status;
- }
-
- static UInt8 CntlStatus[2];
-
- void StartResetDeviceAfterSleep( void )
- {
- OSStatus status;
-
- // First we'll do a GET_STATUS on the control endpoint to
- // see if the device is still responding. Use the interface reference
- // because if the device behaves correctly, it will still be valid
- // else we will just get an error
-
- status = GetStatusEndpointStatus( &gStorageClassInfo.usbPB, GetInterfaceRef(), ResetDeviceAfterSleep, (Ptr) CntlStatus, 0);
- if ( status != kUSBPending )
- {
- //USBExpertStatusLevel(1, gStorageClassInfo.deviceRef, "\pStorage Class: Immed error from GetStatus:" , status);
- gStorageClassInfo.usbPB.usbStatus = status;
- ResetDeviceAfterSleep( &gStorageClassInfo.usbPB );
- }
- }
-
- void ResetDeviceAfterSleep( USBPB *usbPB )
- {
- OSStatus status;
-
- status = usbPB->usbStatus;
- //USBExpertStatusLevel(1, GetInterfaceRef(), "\pStorage Class: Returned error from GetStatus:" , usbPB->usbStatus);
- if ( status != noErr )
- {
- // If we could not get the status of the control endpoint, the device
- // must no longer be responding. Time to do a reset.
- InitParamBlock( gStorageClassInfo.deviceRef, usbPB );
-
- usbPB->usbCompletion = ResetDeviceAfterSleepCompletion;
- status = USBResetDevice( usbPB );
- //USBExpertStatusLevel(1, GetInterfaceRef(), "\pStorage Class: Immed error from Reset:" , status);
- }
-
- // Either the Get_Status succeeded, or the USBResetDevice failed. In either case, we want
- // to clear the sleep condition and if we received a command, process it now.
- if ( status != kUSBPending )
- {
- DecrementAtomic8( &gInSleepReset );
- if ( gInSleepReset < 0)
- {
- gInSleepReset = 0;
- }
-
- if ( gAfterSleepPBPtr != nil )
- {
- OSStatus status;
-
- // We got a command during the reset, send it out now
- status = StorageClassDriverExecuteCommand( gAfterSleepPBPtr );
- if ( status != kRequestPending )
- {
- if(gAfterSleepPBPtr->completionProc != nil)
- {
- gAfterSleepPBPtr->status = kUSBInternalErr;
- (*gAfterSleepPBPtr->completionProc)( gAfterSleepPBPtr );
- }
- }
-
- gAfterSleepPBPtr = nil;
- }
- }
- }
-
- void ResetDeviceAfterSleepCompletion( USBPB *usbPB )
- {
- //USBExpertStatusLevel(1, GetInterfaceRef(), "\pStorage Class: Returned error from Reset:" , usbPB->usbStatus);
- // If no error occurs, reconfigure the device. If an error occurred,
- // do nothing because there isn't anything that can be done.
- if ( usbPB->usbStatus == noErr )
- {
- // Start out at first state and reconfigure the device
- BlockZero( &gStorageClassInfo.usbPB, sizeof(USBPB));
- gStorageClassInfo.usbPB.usbRefcon = kGetFullConfiguration;
- gStorageClassInfo.configurationStatus = kUSBStorageServicesConfigureInProgress;
- StorageDeviceInitiateConfiguration(&gStorageClassInfo.usbPB);
- }
- else
- {
- DecrementAtomic8( &gInSleepReset );
- if ( gInSleepReset < 0)
- {
- gInSleepReset = 0;
- }
-
- if ( gAfterSleepPBPtr != nil )
- {
- if(gAfterSleepPBPtr->completionProc != nil)
- {
- gAfterSleepPBPtr->status = kUSBInternalErr;
- (*gAfterSleepPBPtr->completionProc)( gAfterSleepPBPtr );
- }
-
- gAfterSleepPBPtr = nil;
- }
- }
- }
-
- #pragma mark --
- #pragma mark Name Registry Support Functions
-
- Boolean IsThisTheBootDevice ( USBDeviceRef usbRefNum )
- {
- RegEntryID chosenEntry;
- RegPropertyValueSize size;
- RegPropertyNameBuf propertyName;
- OSErr err;
- Boolean returnValue = false;
- OSType interfaceType;
- DriverGestaltDeviceReferenceResponse deviceRef;
-
- RegistryEntryIDInit (&chosenEntry);
- err = RegistryCStrEntryLookup (nil, "Devices:device-tree:chosen", &chosenEntry);
- if (err == noErr)
- {
- // We were able to find the chosen node, now look for the interface type property.
- CStrCopy (propertyName, "AAPL,bootpath-interfaceType");
-
- // See if property exists
- err = RegistryPropertyGetSize (&chosenEntry, propertyName, &size);
- if (err == noErr)
- {
- // The property exist, get its value.
- size = sizeof (interfaceType);
- err = RegistryPropertyGet (&chosenEntry, propertyName, &interfaceType, &size );
- }
- else
- {
- // There is no Interface type property, which means that we are not in the boot driver stack.
- RegistryEntryIDDispose (&chosenEntry);
- return false;
- }
-
- if ( interfaceType != kdgUSBIntf )
- {
- // The interface type is not USB, therefore, we are not in the boot driver stack.
- RegistryEntryIDDispose (&chosenEntry);
- return false;
- }
-
- // Now look for the device reference property.
- CStrCopy (propertyName, "AAPL,bootpath-deviceReference");
-
- // See if property exists
- err = RegistryPropertyGetSize (&chosenEntry, propertyName, &size);
- if (err == noErr)
- {
- // The property exist, get its value.
- size = sizeof (DriverGestaltDeviceReferenceResponse);
- err = RegistryPropertyGet (&chosenEntry, propertyName, &deviceRef, &size);
- }
- else
- {
- // There is no device reference property, which means that we are not in the boot driver stack.
- return false;
- }
- if ( usbRefNum != deviceRef.usbRef )
- {
- // The device reference found does not match this driver, we are not in the boot driver stack.
- RegistryEntryIDDispose (&chosenEntry);
- return false;
- }
-
- RegistryEntryIDDispose (&chosenEntry);
-
- // If we made it here, then this is indeed the boot driver.
- returnValue = true;
- }
-
- return returnValue;
- }